package cc.opcol.iot.server.server;

import cc.opcol.iot.server.parser.SessionEventHandle;
import cc.opcol.iot.server.util.CRC16Util;
import cc.opcol.iot.server.util.HexUtil;
import cc.opcol.iot.server.util.OpcolUtil;
import cc.opcol.iot.server.util.ThreadUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class IoTSession {
    Logger logger = LoggerFactory.getLogger(IoTSession.class);

    private String id = OpcolUtil.instance.createId();
    private ChannelHandlerContext ctx;
    private long lastActiveTime = new Date().getTime();
    private StringBuffer commandBuffer = new StringBuffer();
    private List<SessionEventHandle> eventHandles = new ArrayList<>();
    private Map<String,Object> cache=new ConcurrentHashMap<>();
    private String deviceType="NOR";

    public void send(byte[] data) {
        //final ByteBuf outBuf= Unpooled.
        ByteBuf out= Unpooled.copiedBuffer(data);
        ctx.channel().writeAndFlush(out);
    }

    public void sendHex(String hex){
        byte[] c= HexUtil.getInstance().hexStringToBye(HexUtil.getInstance().split(hex,2));
        send(c);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public ChannelHandlerContext getCtx() {
        return ctx;
    }

    public void setCtx(ChannelHandlerContext ctx) {
        this.ctx = ctx;
    }

    public long getLastActiveTime() {
        return lastActiveTime;
    }

    public void setLastActiveTime(long lastActiveTime) {
        this.lastActiveTime = lastActiveTime;
    }

    public void onReceived(String hex) {
        logger.debug("Received["+getId()+"]"+hex);
        commandBuffer.append(hex);
        IoTSession thisSession=this;
        ThreadUtil.getInstance().execute(new Runnable() {
            public void run() {
                for (SessionEventHandle sessionEventHandle : eventHandles) {
                    try {
                        sessionEventHandle.onReceived(commandBuffer,thisSession);
                    } catch (Exception e) {
                        logger.error("",e);
                    }
                }
            }
        });

    }

    public void addAllEventHandles(List<SessionEventHandle> parsers) {
        this.eventHandles.addAll(parsers);
    }

    public Map<String, Object> getCache() {
        return cache;
    }

    public void setCache(Map<String, Object> cache) {
        this.cache = cache;
    }

    public void addEventHandle(SessionEventHandle sessionEventHandle) {
        this.eventHandles.add(sessionEventHandle);
    }

    public void removeEventHandle(SessionEventHandle sessionEventHandle) {
        for(SessionEventHandle d:eventHandles){
            if(d.equals(sessionEventHandle)){
                eventHandles.remove(d);
                break;
            }
        }
    }

    public void onActive() {
        IoTSession thisSession=this;
        ThreadUtil.getInstance().execute(new Runnable() {
            public void run() {
                for (SessionEventHandle sessionEventHandle : eventHandles) {
                    try {
                        sessionEventHandle.onActive(thisSession);
                    } catch (Exception e) {
                        logger.error("",e);
                    }
                }
            }
        });
    }

    public void onInActive() {
        IoTSession thisSession=this;
        ThreadUtil.getInstance().execute(new Runnable() {
            public void run() {
                for (SessionEventHandle sessionEventHandle : eventHandles) {
                    try {
                        sessionEventHandle.onInActive(thisSession);
                    } catch (Exception e) {
                        logger.error("",e);
                    }
                }
            }
        });
    }

    public String getDeviceType() {
        return deviceType;
    }

    public void setDeviceType(String deviceType) {
        this.deviceType = deviceType;
    }

    public void login(){
        SessionManager.onSessionLogin(this);
    }
}
